package com.cw.util;

import java.io.*;
import java.net.*;
import java.util.*;
import java.util.zip.*;
import javax.servlet.http.*;
import lombok.extern.log4j.*;
import org.apache.commons.net.ftp.*;

/**
 * @author package com.genomics.ib.item.control
 * @title ItemFtp
 * @Description : FTP 上传下载工具类
 */
@Log4j2
public class ItemFtp {

    private FTPClient ftp;


    /**
     * 获取FTPClient对象
     *
     * @param ftpHost     FTP主机服务器
     * @param ftpPassword FTP 登录密码
     * @param ftpUserName FTP登录用户名
     * @param ftpPort     FTP端口 默认为21
     * @return
     */
    public static FTPClient getFTPClient(String ftpHost, String ftpUserName, String ftpPassword,
						     int ftpPort) {
	  FTPClient ftpClient = new FTPClient();
	  try {
		ftpClient = new FTPClient();
		// 连接FTP服务器
		ftpClient.connect(ftpHost, ftpPort);
		// 登陆FTP服务器
		ftpClient.login(ftpUserName, ftpPassword);
		if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {
		    log.info("未连接到FTP，用户名或密码错误。");
		    ftpClient.disconnect();
		} else {
		    log.info("FTP连接成功。");
		}
	  } catch (SocketException e) {
		e.printStackTrace();
		log.info("FTP的IP地址可能错误，请正确配置。");
	  } catch (IOException e) {
		e.printStackTrace();
		log.info("FTP的端口错误,请正确配置。");
	  }
	  return ftpClient;
    }

    public static void main(String[] args) throws Exception {

	  FTPClient ftp = getFTPClient("192.168.31.211", "anonymous", "qq.123", 21);
	  ftp.setControlEncoding("GBK");//支持中文名文件下载
	  ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
	  ftp.enterLocalPassiveMode();
	  ftp.changeWorkingDirectory("opt");// 转移到FTP服务器目录
	  FTPFile[] fs = ftp.listFiles();
	  for (FTPFile ff : fs) {
		if (ff.getName().equals("ck.xlsx")) {
		    //下载文件
		    OutputStream os = new FileOutputStream(new File("d:/test" + "/" + "ck1.xlsx"));
		    if (ftp.retrieveFile(new String(ff.getName().getBytes("GBK"), "iso-8859-1"), os)) {
			  //文件名编码 和上传的编码一致
			  System.out.println("下载成功");
		    }
		}
	  }
	  ftp.logout();
	  ftp.disconnect();

    }

    /*
     * 从FTP服务器下载文件
     *
     * @param ftpHost FTP IP地址
     *
     * @param ftpUserName FTP 用户名
     *
     * @param ftpPassword FTP用户名密码
     *
     * @param ftpPort FTP端口
     *
     * @param ftpPath FTP服务器中文件所在路径 格式： ftptest/aa
     *
     * @param localPath 下载到本地的位置 格式：H:/download
     *
     * @param fileName 文件名称
     */
    public static void downloadFtpFile(String ftpHost, String ftpUserName, String ftpPassword,
						   int ftpPort, String ftpPath, String localPath,
						   String fileName) {

	  FTPClient ftpClient = null;

	  try {
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		ftpClient.setControlEncoding("GBK"); // 中文支持
		//设置文件编码类型为二进制文件
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		ftpClient.changeWorkingDirectory(ftpPath);

		File localFile = new File(localPath + File.pathSeparator + fileName);
		OutputStream os = new FileOutputStream(localFile);
		//boolean b = ftpClient.retrieveFile(fileName, os);
		boolean b = ftpClient.retrieveFile(new String(fileName.getBytes("GBK"), "iso-8859-1"),
							     os);

		System.out.println(b);
		os.close();
		ftpClient.logout();

	  } catch (FileNotFoundException e) {
		log.info("没有找到" + ftpPath + "文件");
		e.printStackTrace();
	  } catch (SocketException e) {
		log.info("连接FTP失败.");
		e.printStackTrace();
	  } catch (IOException e) {
		e.printStackTrace();
		log.info("文件读取错误。");
		e.printStackTrace();
	  }

    }

    /**
     * 从FTP服务器下载文件(网页)
     *
     * @param ftpHost     FTP IP地址
     * @param ftpUserName FTP 用户名
     * @param ftpPassword FTP用户名密码
     * @param ftpPort     FTP端口
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     */
    public static Boolean downloadFtpFileForWeb(String ftpHost, String ftpUserName,
								String ftpPassword, int ftpPort, String ftpPath,
								String saveAsFileName,
								HttpServletResponse response) {
	  FTPClient ftpClient = null;
	  boolean flag = false;
	  try {
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		//支持中文名文件下载
		ftpClient.setControlEncoding("GBK");
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		// 转移到FTP服务器目录
		ftpClient.changeWorkingDirectory(ftpPath);
		//列出该目录下的所有文件
		FTPFile[] fs = ftpClient.listFiles();
		for (FTPFile ff : fs) {
		    //解决中文名称,确定是当前文件的
		    if (ff.getName().equals(saveAsFileName)) {
			  response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder
				.encode(saveAsFileName, "UTF-8"));
			  //下载文件
			  OutputStream os = response.getOutputStream();
			  if (ftpClient.retrieveFile(
				new String(ff.getName().getBytes("GBK"), "iso-8859-1"), os)) {
				//文件名编码 和上传的编码一致
				flag = true;
				log.info("ftp下载成功");
			  } else {
				log.info("ftp下载失败");
			  }
			  os.flush();
			  os.close();
		    }
		}
		ftpClient.logout();
		ftpClient.disconnect();

	  } catch (FileNotFoundException e) {
		log.info("没有找到" + ftpPath + "文件");
		e.printStackTrace();
	  } catch (SocketException e) {
		log.info("连接FTP失败.");
		e.printStackTrace();
	  } catch (IOException e) {
		e.printStackTrace();
		log.info("文件读取错误。");
		e.printStackTrace();
	  }
	  return flag;
    }

    /**
     * 从FTP服务器下载二进制文件
     *
     * @param ftpHost     FTP IP地址
     * @param ftpUserName FTP 用户名
     * @param ftpPassword FTP用户名密码
     * @param ftpPort     FTP端口
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     */
    public static void downloadFtpFileForWeb1(String ftpHost, String ftpUserName,
							    String ftpPassword, int ftpPort, String ftpPath,
							    String saveAsFileName, HttpServletResponse response)
	  throws UnsupportedEncodingException {
	  FTPClient ftpClient = null;
	  try {
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		//支持中文名文件下载
		ftpClient.setControlEncoding("GBK");
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		// 转移到FTP服务器目录
		ftpClient.changeWorkingDirectory(ftpPath);
		FTPFile[] fs = ftpClient.listFiles();
		for (FTPFile ff : fs) {
		    //解决中文名称
		    if (ff.getName().equals(saveAsFileName)) {
			  InputStream in = ftpClient.retrieveFileStream(
				new String(ff.getName().getBytes("GBK"), "ISO-8859-1"));
			  response.setHeader("content-disposition",
						   "attachment;filename=" + UUIDUtil.uuid() + ".apk");
			  int len = 0;
			  //5.创建数据缓冲区
			  byte[] buffer = new byte[1024];
			  //6.通过response对象获取OutputStream流
			  OutputStream out = response.getOutputStream();
			  //7.将FileInputStream流写入到buffer缓冲区
			  while ((len = in.read(buffer)) > 0) {
				//8.使用OutputStream将缓冲区的数据输出到客户端浏览器
				out.write(buffer, 0, len);
			  }
			  in.close();
			  break;
		    }
		}
		ftpClient.logout();
		ftpClient.disconnect();

	  } catch (FileNotFoundException e) {
		log.info("没有找到" + ftpPath + "文件");
		e.printStackTrace();
	  } catch (SocketException e) {
		log.info("连接FTP失败.");
		e.printStackTrace();
	  } catch (IOException e) {
		e.printStackTrace();
		log.info("文件读取错误。");
		e.printStackTrace();
	  }
    }

    /**
     * InputStream 转换成byte[]
     *
     * @param input
     * @return
     * @throws IOException
     */
    private static byte[] toByteArray(InputStream input) throws IOException {
	  ByteArrayOutputStream output = new ByteArrayOutputStream();
	  byte[] buffer = new byte[1024 * 4];
	  int n = 0;
	  while (-1 != (n = input.read(buffer))) {
		output.write(buffer, 0, n);
	  }
	  return output.toByteArray();
    }


    public static Boolean downloadFtpZipFileForWeb(String ftpHost, String ftpUserName,
								   String ftpPassword, int ftpPort, String ftpPath,
								   List<String> saveAsFileNames,
								   HttpServletResponse response) {
	  FTPClient ftpClient = null;
	  Boolean flag = true;
	  try {
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		//支持中文名文件下载
		ftpClient.setControlEncoding("GBK");
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		// 转移到FTP服务器目录
		ftpClient.changeWorkingDirectory(ftpPath);
		ZipOutputStream zip = null;
		try {
		    String zipName = "new.zip";
		    response.setContentType("APPLICATION/OCTET-STREAM");
		    response.setHeader("Content-Disposition", "attachment; filename=" + zipName);
		    //获取到zip输出流
		    zip = new ZipOutputStream(response.getOutputStream());
		    FTPFile[] fs = ftpClient.listFiles();
		    if (ftpClient.isConnected()) {
			  ftpClient.disconnect();
			  ftpClient = null;
		    }
		    for (FTPFile ff : fs) {
			  for (String fileName : saveAsFileNames) {
				if (ff.getName().equals(fileName)) {
				    ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
				    ftpClient.setControlEncoding("GBK");//支持中文名文件下载
				    ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
				    ftpClient.enterLocalPassiveMode();
				    ftpClient.changeWorkingDirectory(ftpPath);// 转移到FTP服务器目录
				    InputStream is = ftpClient.retrieveFileStream(
					  new String(fileName.getBytes("GBK"), "ISO-8859-1"));
				    doCompress(is, fileName, zip);
				}
			  }
		    }
		    response.flushBuffer();
		} catch (Exception e) {
		    flag = false;
		    e.printStackTrace();
		} finally {
		    if (zip != null) {
			  try {
				zip.close();
			  } catch (IOException e) {
			  }
		    }
		}
		ftpClient.logout();
		ftpClient.disconnect();

	  } catch (FileNotFoundException e) {
		log.info("没有找到" + ftpPath + "文件");
		flag = false;
		e.printStackTrace();
	  } catch (SocketException e) {
		log.info("连接FTP失败.");
		flag = false;
		e.printStackTrace();
	  } catch (IOException e) {
		e.printStackTrace();
		log.info("文件读取错误。");
		flag = false;
		e.printStackTrace();
	  }
	  return flag;
    }

    public static void doCompress(InputStream fis, String fileName, ZipOutputStream out)
	  throws IOException {
	  byte[] buffer = new byte[1024];
	  out.putNextEntry(new ZipEntry(fileName));
	  int len = 0;
	  // 读取文件的内容,打包到zip文件
	  while ((len = fis.read(buffer)) > 0) {
		out.write(buffer, 0, len);
		out.flush();
	  }
	  out.closeEntry();
	  fis.close();
    }

    /**
     * Description: 向FTP服务器上传文件
     *
     * @param ftpHost     FTP服务器hostname
     * @param ftpUserName 账号
     * @param ftpPassword 密码
     * @param ftpPort     端口
     * @param ftpPath     FTP服务器中文件所在路径 格式： ftptest/aa
     * @param fileName    ftp文件名称
     * @param input       文件流
     * @return 成功返回true，否则返回false
     */
    public static boolean uploadFile(String ftpHost, String ftpUserName, String ftpPassword,
						 int ftpPort, String ftpPath, String fileName,
						 InputStream input) {
	  boolean success = false;
	  FTPClient ftpClient = null;
	  try {
		int reply;
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
		    ftpClient.disconnect();
		    return success;
		}
		ftpClient.setControlEncoding("UTF-8"); // 中文支持
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		ftpClient.changeWorkingDirectory(ftpPath);

		ftpClient.storeFile(fileName, input);

		//
		uploadFile(fileName, input);

		input.close();
		ftpClient.logout();
		success = true;
	  } catch (IOException e) {
		e.printStackTrace();
	  } finally {
		if (ftpClient.isConnected()) {
		    try {
			  ftpClient.disconnect();
		    } catch (IOException ioe) {
		    }
		}
	  }
	  return success;
    }

    public static boolean uploadFiles(String ftpHost, String ftpUserName, String ftpPassword,
						  int ftpPort, String ftpPath, List<String> fileNames,
						  List<InputStream> inputs, String newFile) {
	  boolean result = false;
	  FTPClient ftpClient = null;
	  try {
		int reply;
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
		    ftpClient.disconnect();
		    return result;
		}
		ftpClient.setControlEncoding("UTF-8"); // 中文支持
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

		//ftpClient.setFileTransferMode(FTP.STREAM_TRANSFER_MODE);

		//创建文件夹
		mkDir(ftpClient, newFile);
		ftpClient.enterLocalPassiveMode();
		ftpClient.changeWorkingDirectory(ftpPath);
		for (int i = 0; i < fileNames.size(); i++) {
		    String fileName = fileNames.get(i);
		    InputStream input = inputs.get(i);
		    //解决中文名称
		    fileName = new String(fileName.getBytes("GBK"), "iso-8859-1");
		    boolean b = ftpClient.storeFile(fileName, input);
		    if (b) {
			  result = true;
		    } else {
			  result = false;
		    }
		    input.close();
		}

		ftpClient.logout();

	  } catch (IOException e) {
		e.printStackTrace();
	  } finally {
		if (ftpClient.isConnected()) {
		    try {
			  ftpClient.disconnect();
		    } catch (IOException ioe) {
		    }
		}
	  }
	  return result;
    }

    /**
     * 删除文件
     *
     * @param ftpHost
     * @param ftpUserName
     * @param ftpPassword
     * @param ftpPort
     * @param ftpPath
     * @param saveAsFileName
     * @return
     * @throws IOException
     */
    public static Boolean deleteFile(String ftpHost, String ftpUserName, String ftpPassword,
						 int ftpPort, String ftpPath, String saveAsFileName)
	  throws IOException {
	  boolean result = false;
	  FTPClient ftpClient = null;
	  try {
		int reply;
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
		    ftpClient.disconnect();
		    return result;
		}
		ftpClient.setControlEncoding("UTF-8"); // 中文支持
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);

		ftpClient.enterLocalPassiveMode();
		ftpClient.changeWorkingDirectory(ftpPath);// 转移到FTP服务器目录
		//解决中文名称
		saveAsFileName = new String(saveAsFileName.getBytes("GBK"), "iso-8859-1");
		boolean b = ftpClient.deleteFile(saveAsFileName);
		if (!b) {
		    result = false;
		} else {
		    result = true;
		}
		ftpClient.logout();

	  } catch (IOException e) {
		e.printStackTrace();
	  } finally {
		if (ftpClient.isConnected()) {
		    try {
			  ftpClient.disconnect();
		    } catch (IOException ioe) {
		    }
		}
	  }
	  return result;
    }

    /**
     * 批量删除文件
     *
     * @param ftpHost
     * @param ftpUserName
     * @param ftpPassword
     * @param ftpPort
     * @param ftpPaths
     * @param saveAsFileNames
     * @return
     * @throws IOException
     */
    public static Boolean deleteFiles(String ftpHost, String ftpUserName, String ftpPassword,
						  int ftpPort, List<String> ftpPaths,
						  List<String> saveAsFileNames) throws IOException {
	  boolean result = false;
	  FTPClient ftpClient = null;
	  try {
		int reply;
		ftpClient = getFTPClient(ftpHost, ftpUserName, ftpPassword, ftpPort);
		reply = ftpClient.getReplyCode();
		if (!FTPReply.isPositiveCompletion(reply)) {
		    ftpClient.disconnect();
		    return result;
		}
		ftpClient.setControlEncoding("UTF-8"); // 中文支持
		ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
		ftpClient.enterLocalPassiveMode();
		for (int i = 0; i < ftpPaths.size(); i++) {
		    ftpClient.changeWorkingDirectory(ftpPaths.get(i));// 转移到FTP服务器目录

		    //解决中文名称
		    String saveAsFileName = new String(saveAsFileNames.get(i).getBytes("GBK"),
								   "iso-8859-1");
		    boolean b = ftpClient.deleteFile(saveAsFileName);
		    if (!b) {
			  result = false;
		    } else {
			  result = true;
		    }
		}

		ftpClient.logout();

	  } catch (IOException e) {
		e.printStackTrace();
	  } finally {
		if (ftpClient.isConnected()) {
		    try {
			  ftpClient.disconnect();
		    } catch (IOException ioe) {
		    }
		}
	  }
	  return result;
    }


    /**
     * 选择上传的目录，没有创建目录
     *
     * @param ftpPath 需要上传、创建的目录
     * @return
     */
    public static boolean mkDir(FTPClient ftpClient, String ftpPath) {
	  if (!ftpClient.isConnected()) {
		return false;
	  }
	  try {
		// 将路径中的斜杠统一
		char[] chars = ftpPath.toCharArray();
		StringBuffer sbStr = new StringBuffer(256);
		for (int i = 0; i < chars.length; i++) {
		    if ('\\' == chars[i]) {
			  sbStr.append(File.pathSeparator);
		    } else {
			  sbStr.append(chars[i]);
		    }
		}
		ftpPath = sbStr.toString();
		// System.out.println("ftpPath:" + ftpPath);
		if (ftpPath.indexOf(File.pathSeparator) == -1) {
		    // 只有一层目录
		    ftpClient.makeDirectory(new String(ftpPath.getBytes(), "iso-8859-1"));
		    ftpClient.changeWorkingDirectory(new String(ftpPath.getBytes(), "iso-8859-1"));
		} else {
		    // 多层目录循环创建
		    String[] paths = ftpPath.split(File.pathSeparator);
		    for (int i = 0; i < paths.length; i++) {
			  ftpClient.makeDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
			  ftpClient.changeWorkingDirectory(new String(paths[i].getBytes(), "iso-8859-1"));
		    }
		}
		return true;
	  } catch (Exception e) {
		e.printStackTrace();
		return false;
	  }
    }

    //ftp服务器ip地址
    private static String FTP_ADDRESS = "192.168.31.211";
    //端口号
    private static int FTP_PORT = 21;
    //用户名
    private static String FTP_USERNAME = "ftpsrm";
    //密码
    private static String FTP_PASSWORD = "FtpQq.123456";
    //图片路径
    public static String FTP_BASEPATH = "/data/ftp/pub/app";


    //参数传过来了文件和文件的输入流
    public static boolean uploadFile(String originFileName, InputStream input) {
	  boolean success = false;
	  //这是最开始引入的依赖里的方法
	  FTPClient ftp = new FTPClient();
	  ftp.setControlEncoding("utf-8");
	  try {
		int reply;
		ftp.connect(FTP_ADDRESS, FTP_PORT);// 连接FTP服务器
		ftp.login(FTP_USERNAME, FTP_PASSWORD);// 登录
		reply = ftp.getReplyCode();//连接成功会的到一个返回状态码
		System.out.println(reply);//可以输出看一下是否连接成功
		ftp.setFileType(FTPClient.BINARY_FILE_TYPE);//设置文件类型
		ftp.changeWorkingDirectory(FTP_BASEPATH);//修改操作空间
		//对了这里说明一下你所操作的文件夹必须要有可读权限，chomd 777 文件夹名//这里我就是用的我的home文件夹
		ftp.storeFile(originFileName, input);//这里开始上传文件
		if (!FTPReply.isPositiveCompletion(reply)) {
		    ftp.disconnect();
		    log.error("pdf连接失败");
		    return success;
		}
		log.info("pdf连接成功");
		input.close();
		ftp.logout();
		success = true;
	  } catch (IOException e) {
		e.printStackTrace();
	  } finally {
		if (ftp.isConnected()) {
		    try {
			  ftp.disconnect();
		    } catch (IOException ioe) {
		    }
		}
	  }
	  return success;
    }

}
